package com.sharing;

/**
 * 如果设置两个线程，一个共享变量，一个线程对这个变量加500次，一个线程对这个变量减500次
 * 那最后结果会是0吗？可以运行下面的方法试一下
 * 实际上，这个结果可能是0、正数、负数
 * 原因是，Java语言，在运行前会进行编译，编译成字节码。
 * 而从字节码层面来理解，自增、自减，并不是一个原子操作
 * 下面用自增的字节码来解释
 * 如下：
 *      getstatic  i  //获取静态变量num的值
 *      iconst_1        //准备常量1
 *      iadd            //自增
 *      putstatic i     //将修改后的值存入静态变量i
 * 而在Java的内存模型中，自增自减需要和主内存进行交互
 * 也就是说，如果两个线程，t1和t2，t1自增，t2自减
 * 那么每次t1都会和主内存交互，t2也会和主内存交互，每次交互都会去拿取共享变量
 * 如果是单线程执行，这样的代码是不会有问题的，它们会交错执行
 * 那如果多线程，我们以两个线程举例
 * 当t1拿取主内存共享变量后，还没处理完，t2就拿了主内存共享变量，而这时t1还没有更新完加进去，t2就拿走了，那么t2拿走时，变量还是0
 * t1处理完了，写入主内存，500
 * 那t2也处理完了，我们要知道，这里是直接覆盖写入的，那么t2写入就是-500，直接给覆盖掉了
 * 那么其他两种情况也是如此。
 */
public class ShareProblem {
    static int num = 0;
    public static void main(String[] args) throws InterruptedException {
        test();
    }
    public static void test() throws InterruptedException {
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 500; i++) {
                num++;
            }
        },"t1");
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 500; i++) {
                num--;
            }
        },"t2");
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(num);
    }
}
